package com.lagou.mapper;

import com.lagou.model.Request;
import com.lagou.model.Response;
import com.lagou.servlet.HttpServlet;
import com.lagou.v4.LifeCycle;
import com.lagou.v4.container.Context;
import com.lagou.v4.container.Engine;
import com.lagou.v4.container.Host;
import com.lagou.v4.container.Service;
import com.lagou.v4.container.Wrapper;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Kirito
 * @description: 封装url到host、context、wrapper映射关系
 * @date 2020/05/03
 */
public class Mapper implements LifeCycle {

    private List<MappedHost> hosts = new ArrayList<>();

    private Service service;

    public void setService(Service service) {
        this.service = service;
    }

    @Override
    public void init() throws Exception {

        Engine engine = service.getEngine();
        if (null == engine) return;

        List<Host> hostList = engine.getHosts();
        for (Host host : hostList) {
            MappedHost mappedHost = new MappedHost(host.getName(), host, getMappedContext(host.getContexts()));
            hosts.add(mappedHost);
        }

    }

    private List<MappedContext> getMappedContext(List<Context> contextList) {
        List<MappedContext> mappedContexts = new ArrayList<>(contextList.size());
        for (Context context : contextList) {

            MappedContext mappedContext = new MappedContext(context.getContextPath(), context, getMappedWrapper(context.getWrappers()));

            mappedContexts.add(mappedContext);
        }

        return mappedContexts;
    }

    private List<MappedWrapper> getMappedWrapper(List<Wrapper> wrappers) {
        List<MappedWrapper> mappedWrappers = new ArrayList<>(wrappers.size());
        for (Wrapper wrapper : wrappers) {
            MappedWrapper mappedWrapper = new MappedWrapper(wrapper.getServletName(), wrapper);
            mappedWrappers.add(mappedWrapper);
        }
        return mappedWrappers;
    }

    @Override
    public void start() throws Exception {

    }

    public void invoke(Request request, Response response) throws Exception {

        String host = request.getHost();
        String url = request.getUrl();
        MappedHost mappedHost = this.hosts.stream().filter(h -> host.equals(h.name)).findFirst().orElse(null);
        if (null == mappedHost) return;

        MappedContext mappedContext = mappedHost.mappedContexts.stream().filter(c -> url.contains(c.object.getContextPath())).findFirst().orElse(null);
        if (null == mappedContext) return;

        MappedWrapper mappedWrapper = mappedContext.mappedWrappers.stream().filter(w -> url.contains(w.object.getUrlPattern())).findFirst().orElse(null);

        if (mappedWrapper == null) {
            response.outPutStaticResource(url);
        } else {
            HttpServlet servlet = mappedWrapper.object.getServlet();
            servlet.service(request, response);
        }
    }

    protected abstract static class MapElement<T> {

        public final String name;
        public final T object;

        public MapElement(String name, T object) {
            this.name = name;
            this.object = object;
        }
    }

    protected static final class MappedHost extends MapElement<Host> {

        private List<MappedContext> mappedContexts;

        public MappedHost(String name, Host object, List<MappedContext> mappedContexts) {
            super(name, object);
            this.mappedContexts = mappedContexts;
        }
    }

    protected static final class MappedContext extends MapElement<Context> {

        private List<MappedWrapper> mappedWrappers;

        public MappedContext(String name, Context object, List<MappedWrapper> mappedWrappers) {
            super(name, object);
            this.mappedWrappers = mappedWrappers;
        }
    }

    protected static class MappedWrapper extends MapElement<Wrapper> {
        public MappedWrapper(String name, Wrapper object) {
            super(name, object);
        }
    }
}
